//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 6/12/2008 4:15:44 PM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using System.Collections.Generic;
using System.Drawing;
using MapWindow.Drawing;
using MapWindow.Geometries;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MapWindow.DirectX
{


    /// <summary>
    /// EnvelopeDX
    /// </summary>
    public class ImageDX : RenderBaseDX
    {
        #region Private Variables


        private PolygonSymbolizer _symbolizer;

        private PositionColoredVC _borderVertices;
        private PositionTexturedVC _fillVertices;
        private IndexCollection _fillIndices;
        private IndexCollection _borderIndices;


        private Texture _texture;
        private readonly float _tTop;
        private readonly float _tLeft;
        private readonly float _tRight;
        private readonly float _tBottom;

        /// <summary>
        /// Texture coordinates range from 0 (top) to 1 (bottom).  This float indicates
        /// where the top of this image should be on the texture.
        /// </summary>
        public float TextureTop
        {
            get { return _tTop; }
        }

        /// <summary>
        /// Texture coordinates range from 0 (top) to 1 (bottom).  This float indicates
        /// where the bottom of this image should be on the texture.
        /// </summary>
        public float TextureBottom
        {
            get { return _tBottom; }
        }


        /// <summary>
        /// Texture coordinates range from 0 (left) to 1 (right).  This float indicates
        /// where the left of this image should be on the texture.
        /// </summary>
        public float TextureLeft
        {
            get { return _tLeft; }
        }

        /// <summary>
        /// Texture coordinates range from 0 (left) to 1 (right).  This float indicates
        /// where the left of this image should be on the texture.
        /// </summary>
        public float TextureRight
        {
            get { return _tRight; }
        }

        /// <summary>
        /// Gets the texture used for this image.
        /// </summary>
        public Texture Texture
        {
            get { return _texture; }
        }



        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of EnvelopeDX
        /// </summary>
        public ImageDX()
        {
            _symbolizer = new PolygonSymbolizer();
           
        }

        /// <summary>
        /// Just the boundaries
        /// </summary>
        /// <param name="borderColor"></param>
        /// <param name="envelope"></param>
        public ImageDX(Color borderColor, IEnvelope envelope)
        {
            _symbolizer = new PolygonSymbolizer();
            _symbolizer.OutlineSymbolizer.SetFillColor(borderColor);
            base.Envelope = envelope;
        }

        /// <summary>
        /// Creates a new image where the entire texture is used.
        /// </summary>
        /// <param name="borderColor"></param>
        /// <param name="envelope"></param>
        /// <param name="texture"></param>
        public ImageDX(Color borderColor, IEnvelope envelope, Texture texture)
        {
            _symbolizer = new PolygonSymbolizer();
            _symbolizer.OutlineSymbolizer.SetFillColor(borderColor);
            base.Envelope = envelope;
            _texture = texture;
            _tTop = 0;
            _tLeft = 0;
            _tRight = 1;
            _tBottom = 1;
            
        }

        /// <summary>
        /// Creates a Textured version of the ImageDX
        /// </summary>
        /// <param name="borderColor">The Color for the border of the ImageDX</param>
        /// <param name="envelope">The Envelope confining the image</param>
        /// <param name="texture">The texture to use</param>
        /// <param name="Position"></param>
        public ImageDX(Color borderColor, IEnvelope envelope, Texture texture, Quadrants Position)
        {
            _symbolizer = new PolygonSymbolizer();
            _symbolizer.OutlineSymbolizer.SetFillColor(borderColor);
            base.Envelope = envelope;
            _texture = texture;
            switch(Position)
            {
                case Quadrants.NorthWest:
                    _tTop = 0;
                    _tLeft = 0;
                    _tRight = .5F;
                    _tBottom = .5F;
                    break;
                case Quadrants.NorthEast:
                    _tTop = 0;
                    _tLeft = .5F;
                    _tRight = 1;
                    _tBottom = .5F;
                    break;
                case Quadrants.SouthWest:
                    _tTop = .5F;
                    _tLeft = 0;
                    _tRight = .5F;
                    _tBottom = 1;
                    break;
                case Quadrants.SouthEast:
                    _tTop = .5F;
                    _tLeft = .5F;
                    _tRight = 1;
                    _tBottom = 1;
                    break;            
            }
           
        }

        /// <summary>
        /// Constructs a new image that will correspond to the specified sub-portion of the given image
        /// </summary>
        /// <param name="borderColor"></param>
        /// <param name="envelope"></param>
        /// <param name="texture"></param>
        /// <param name="tTop"></param>
        /// <param name="tLeft"></param>
        /// <param name="tBottom"></param>
        /// <param name="tRight"></param>
        public ImageDX(Color borderColor, IEnvelope envelope, Texture texture, float tTop, float tLeft, float tBottom, float tRight)
        {
            _symbolizer = new PolygonSymbolizer();
            _symbolizer.OutlineSymbolizer.SetFillColor(borderColor);
            base.Envelope = envelope;
            _texture = texture;
            _tTop = tTop;
            _tLeft = tLeft;
            _tRight = tRight;
            _tBottom = tBottom;
        
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates a child image from the same texture but only showing the upper left quadrant
        /// </summary>
        /// <param name="borderColor">The border color of the new image</param>
        /// <returns>An ImageDX of the specified quadrant</returns>
        public ImageDX NorthWest(Color borderColor)
        {

            float pw = _tRight - _tLeft; 
            float ph = _tBottom - _tTop;
            float tLeft = _tLeft;
            float tTop = _tTop;
            float tRight = _tLeft + pw / 2;
            float tBottom = _tTop + ph / 2;
            IEnvelope env = new Envelope();
            env.SetExtents(Envelope.Minimum.X, Envelope.Minimum.Y + Envelope.Height/2, Envelope.Maximum.X - Envelope.Width/2, Envelope.Maximum.Y);
            return new ImageDX(borderColor, env, _texture, tTop, tLeft, tBottom, tRight);
            
        }

        /// <summary>
        /// Creates a child image from the same texture but only showing the upper right quadrant
        /// </summary>
        /// <param name="borderColor">The border color of the new image</param>
        /// <returns>An ImageDX of the specified quadrant</returns>
        public ImageDX NorthEast(Color borderColor)
        {
            float pw = _tRight - _tLeft;
            float ph = _tBottom - _tTop;
            float tLeft = _tLeft + pw/2;
            float tTop = _tTop;
            float tRight = _tRight;
            float tBottom = _tTop + ph / 2;
            IEnvelope env = new Envelope();
            env.SetExtents(Envelope.Minimum.X + Envelope.Width/2, Envelope.Minimum.Y + Envelope.Height / 2, Envelope.Maximum.X, Envelope.Maximum.Y);
            return new ImageDX(borderColor, env, _texture, tTop, tLeft, tBottom, tRight);
           
        }

        /// <summary>
        /// Creates a child image from the same texture but only showing the lower right quadrant
        /// </summary>
        /// <param name="borderColor">The border color of the new image</param>
        /// <returns>An ImageDX of the specified quadrant</returns>
        public ImageDX SouthEast(Color borderColor)
        {
            float pw = _tRight - _tLeft;
            float ph = _tBottom - _tTop;
            float tLeft = _tLeft + pw / 2;
            float tTop = _tTop + ph/2;
            float tRight = _tRight;
            float tBottom = _tBottom;
            IEnvelope env = new Envelope();
            env.SetExtents(Envelope.Minimum.X + Envelope.Width / 2, Envelope.Minimum.Y , Envelope.Maximum.X, Envelope.Minimum.Y + Envelope.Height/2);
            return new ImageDX(borderColor, env, _texture, tTop, tLeft, tBottom, tRight);

        }

        /// <summary>
        /// Creates a child image from the same texture but only showing the lower left quadrant
        /// </summary>
        /// <param name="borderColor">The border color of the new image</param>
        /// <returns>An ImageDX of the specified quadrant</returns>
        public ImageDX SouthWest(Color borderColor)
        {

            float pw = _tRight - _tLeft;
            float ph = _tBottom - _tTop;
            float tLeft = _tLeft ;
            float tTop = _tTop + ph / 2;
            float tRight = _tLeft + pw / 2;
            float tBottom = _tBottom;
            IEnvelope env = new Envelope();
            env.SetExtents(Envelope.Minimum.X, Envelope.Minimum.Y, Envelope.Maximum.X - Envelope.Width / 2, Envelope.Minimum.Y + Envelope.Height/2);
            return new ImageDX(borderColor, env, _texture, tTop, tLeft, tBottom, tRight);

        }

        /// <summary>
        /// Obtains one of the four sub-quadrants for this image
        /// </summary>
        /// <param name="borderColor"></param>
        /// <param name="position">0:NW, 1:NW, 2:SE, 3:SW</param>
        /// <returns></returns>
        public ImageDX ChildImage(Color borderColor, Quadrants position)
        {
            switch (position)
            {
                case Quadrants.NorthWest: return NorthWest(borderColor); 
                case Quadrants.NorthEast: return NorthEast(borderColor);
                case Quadrants.SouthWest: return SouthWest(borderColor);
                case Quadrants.SouthEast: return SouthEast(borderColor);
            }
            return null;
 
        }

        #endregion

        #region Properties



        #endregion




        #region IRenderableDX Members

     

        /// <summary>
        /// Dispose
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            //if (components != null && disposing)
            //{
            //    components.Dispose();
            //}
            if(_borderIndices != null)_borderIndices.Dispose();
            if(_borderVertices != null)_borderVertices.Dispose();
            if(_fillIndices != null) _fillIndices.Dispose();
            if(_fillVertices != null)_fillVertices.Dispose();
            _texture = null; // Don't dispose this since it is assumed to be a link to
            // a texture that is controlled somewhere else.
        }

        /// <summary>
        /// Disposes, but also sets _isInitialized to false
        /// </summary>
        public void Close()
        {
            if (_borderIndices != null) _borderIndices.Dispose();
            if (_borderVertices != null) _borderVertices.Dispose();
            if (_fillIndices != null) _fillIndices.Dispose();
            if (_fillVertices != null) _fillVertices.Dispose();
            _texture = null; // Don't dispose this since it is assumed to be a link to
            IsInitialized = false;
        }

        /// <summary>
        /// Performs the actual drawing to the 3D device
        /// </summary>
        /// <param name="args">A DrawArgsDX parameter</param>
        protected override void OnDraw(DrawArgsDX args)
        {
         

            if (_symbolizer != null && _symbolizer.GetFillColor() != Color.Transparent)
            {
                args.Device.SetTexture(0, _texture);
                _fillIndices.BeforeDrawing(args.Device);
                _fillVertices.BeforeDrawing(args.Device);
                args.Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);
                _fillIndices.AfterDrawing(args.Device);
                _fillVertices.AfterDrawing(args.Device);
                args.Device.SetTexture(0, null);
            }

            // Draw border lines
            
            _borderVertices.BeforeDrawing(args.Device);
            _borderIndices.BeforeDrawing(args.Device);
            args.Device.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, 4, 0, 4);
            _borderIndices.AfterDrawing(args.Device);
            _borderVertices.AfterDrawing(args.Device);
            
           

          //  device.RenderState.ZBufferEnable = false;
            
        }

        /// <summary>
        /// Initializes the vertices and indices
        /// </summary>
        public override void Initialize(DrawArgsDX args)
        {
            _borderVertices = new PositionColoredVC();
            _fillVertices = new PositionTexturedVC();
            Vector3 topLeft = new Vector3(Convert.ToSingle(Envelope.Minimum.X), Convert.ToSingle(Envelope.Maximum.Y), -.05F);
            Vector3 topRight = new Vector3(Convert.ToSingle(Envelope.Maximum.X), Convert.ToSingle(Envelope.Maximum.Y), -.05F);
            Vector3 bottomLeft = new Vector3(Convert.ToSingle(Envelope.Minimum.X), Convert.ToSingle(Envelope.Minimum.Y), -.05F);
            Vector3 bottomRight = new Vector3(Convert.ToSingle(Envelope.Maximum.X), Convert.ToSingle(Envelope.Minimum.Y), -.05F);
            
            // Border
            Color borderColor = Color.Red;
            if (_symbolizer != null)
            {
                borderColor = _symbolizer.OutlineSymbolizer.GetFillColor();
            }
            _borderVertices.Color = borderColor;
            _borderVertices.AddCoordinate(topLeft);
            _borderVertices.AddCoordinate(topRight);
            _borderVertices.AddCoordinate(bottomLeft);
            _borderVertices.AddCoordinate(bottomRight);
            
            // Interior
            _fillVertices.AddCoordinate(topLeft, _tLeft, _tTop);
            _fillVertices.AddCoordinate(topRight, _tRight, _tTop);
            _fillVertices.AddCoordinate(bottomLeft, _tLeft, _tBottom);
            _fillVertices.AddCoordinate(bottomRight, _tRight, _tBottom);


            _fillIndices = new IndexCollection(1);

            List<int> values = new List<int>();
            values.Add(0);
            values.Add(1);
            values.Add(1);
            values.Add(3);
            values.Add(3);
            values.Add(2);
            values.Add(2);
            values.Add(0);
            _borderIndices = new IndexCollection(values);
            IsInitialized = true;

        }

       

       

        /// <summary>
        /// 
        /// </summary>
        public PolygonSymbolizer Symbolizer
        {
            get { return _symbolizer; }
            set { _symbolizer = value; }
        }

        #endregion

     
    }
}
